<?php
/**
 * dar数据表
 *
 * @package util.dar
 * @version $Id: IDarTable.php 323 2008-05-14 05:49:20Z iwind $
 * @since 0.0.3
 */
class IDarTable extends IObject {
	private $fields = array();
	private $columns = array();
	private $name;
	private $id;
	private $idName;
	
	/**
	 * Enter description here...
	 *
	 * @var IDarModel
	 */
	private $model;
	
	/**
	 * 构造器
	 * 
	 * @since 0.0.3
	 */
	public function __construct() {

	}
	
	/**
	 * 取得所有字段
	 *
	 * @return array
	 * @since 0.0.3
	 */
	public function getFields() {
		return $this->fields;
	}
	
	/**
	 * 设置表名称
	 *
	 * @param string $name 名称
	 * @since 0.0.3
	 */
	public function setName($name) {
		$this->name = $name;
	}
	
	/**
	 * 取得表名称
	 *
	 * @return string
	 * @since 0.0.3
	 */
	public function getName() {
		return $this->name;
	}
	
	/**
	 * 添加字段
	 *
	 * @param IDarField $field 字段
	 * @since 0.0.3
	 */
	public function addField(IDarField $field) {
		$this->columns[strtolower($field->getColumn())] = $field;
		$this->fields[strtolower($field->getName())] = $field;
		$field->setTable($this);
	}

	/**
	 * 取得字段
	 *
	 * @param string $fieldName 字段名
	 * @return IDarField
	 * @since 0.0.3
	 */
	public function getField($fieldName) {
		$fieldName = strtolower($fieldName);
		if ($this->hasField($fieldName)) {
			return $this->fields[$fieldName];
		}
		else {
			throw new IDarFieldNotFoundException("model '" . $this->model->getName() .  "' table '" . $this->getName() . "' field named by '{$fieldName}' does not exist");
		}
	}
	
	/**
	 * 使用字段的列名查找字段
	 *
	 * @param string $column 列名
	 * @return IDarField
	 * @since 0.0.3
	 */
	public function getFieldByColumn($column) {
		$column = strtolower($column);
		if ($this->hasColumn($column)) {
			return $this->columns[$column];
		}
		else {
			throw new IDarException("column named by '{$column}' does not exist");
		}
	}
	
	/**
	 * 判断表中是否有特定的字段
	 *
	 * @param string $fieldName 字段名
	 * @return boolean
	 * @since 0.0.3
	 */
	public function hasField($fieldName) {
		return array_key_exists($fieldName, $this->fields);
	}
	
	/**
	 * 判断表中是否有特定的列
	 *
	 * @param string $column 列名
	 * @return boolean
	 * @since 0.0.3
	 */
	public function hasColumn($column) {
		return array_key_exists($column, $this->columns);
	}
	
	/**
	 * 设置唯一标识字段
	 *
	 * @param IDarField $id 唯一标识字段
	 * @since 0.0.3
	 */
	public function setId(IDarField $id) {
		$this->id = $id;
	}
	
	/**
	 * 设置唯一标识字段的名称
	 *
	 * @param string $idName ID名称
	 * @since 0.0.3
	 */
	public function setIdName($idName) {
		$this->idName = $idName;
	}
	
	/**
	 * 得到主键
	 *
	 * @return IDarField
	 * @since 0.0.3
	 */
	public function getPrimaryKey() {
		foreach ($this->fields as $field) {
			if ($field->isPrimaryKey()) {
				return $field;
			}
		}
		return null;
	}
	
	/**
	 * 得到行的唯一标识字段
	 *
	 * @return IDarField
	 * @since 0.0.3
	 */
	public function getId() {
		if ($this->id == null) {
			if ($this->idName != null) {
				$this->id = $this->getField($this->idName)	;
			}
			else {
				$this->id = $this->getPrimaryKey();
			}
		}
		if ($this->id == null) {
			$this->id = $this->getField("id");
			if ($this->id == null) {
				throw new IDarException("no id field is defined in table " . $this->getName());
			}
		}
		return $this->id;
	}
	
	/**
	 * 设置包含该表的模型
	 *
	 * @param IDarModel $model 模型
	 * @since 0.1
	 */
	public function setModel(IDarModel $model) {
		$this->model = $model;
	}
	
	/**
	 * 取得包含该表的模型
	 *
	 * @return IDarModel
	 * @since 0.1
	 */
	public function getModel() {
		return $this->model;
	}
	
	/**
	 * 从配置中生成一个表
	 * 
	 * $config形如：
	 * <code>
	 * array(
	 *	 "tblName" => "tbl_category",
	 *	 "idName" => "id",
	 *	 "fields" => array("id", "name")
	 * )
	 * </code>
	 *
	 * @param string $modelClass 所属模型类名
	 * @param array $config 配置
	 * @return array
	 * @since 0.2.1
	 */
	public static function create($modelClass, array $config) {
		$table = new IDarTable();
		if (array_key_exists("tblName", $config)) {
			$table->setName($config["tblName"]);
		}
		else {
			$table->setName(native::nameToC($class));//使用类名作为表名
		}
		if (array_key_exists("idName", $config)) {
			$table->setIdName($config["idName"]);
		}

		if (!array_key_exists("fields", $config)) {
			throw new IDarException("model '{$class}' fields is not defined");
		}
		$fieldsConfig = $config["fields"];
		if (!is_array($fieldsConfig)) {//throw exception
			throw new IDarException("model '{$class}' fields is invalid");
		}
		foreach ($fieldsConfig as $name=>$fieldConfig) {
			$field = new IDarField();
			if (!is_array($fieldConfig)) {
				if (is_integer($fieldConfig) || is_string($fieldConfig)) {
					$field->setName($fieldConfig);
					$table->addField($field);
					continue;
				}
				else {				
					throw new IDarException(gettype($fieldConfig) . " data type can't be a field name");	
				}
			}
			if (is_integer($name) || is_string($name)) {
				$field->setName($name);//设置名称
			}
			
			foreach ($fieldConfig as $key=>$value) {
				if (in_array($key, array("name", "type", "column", "maxLength", "notNull", "primaryKey", "autoIncrement", "binary", "unsigned", "hasDefault", "defaultValue", "virtual", "expression"), true)) {
					$setter = "set" . $key;
					$field->$setter($value);
				}
				else if (in_array($key, array("hasOne", "hasMany", "belongsTo"), true) && is_array($value)) {
					if (!array_key_exists("type", $value)) {
						$value["type"] = $key;
					}
					$field->setRelation($value);
				}
			}
			
			//primarykey
			if (isset($config["idName"]) && $config["idName"] === $field->getName()) {
				$field->setPrimaryKey(true);
			}
			
			$table->addField($field);
		}
		$mapping = (isset($config["mapping"]) && is_array($config["mapping"]))?$config["mapping"]:array();
		foreach ($mapping as $name=>$fieldConfig) {
			$field = new IDarField();
			if (!is_array($fieldConfig)) {
				if (is_integer($fieldConfig) || is_string($fieldConfig)) {
					$field->setName($fieldConfig);
					$table->addField($field);
					continue;
				}
				else {				
					throw new IDarException(gettype($fieldConfig) . " data type can't be a field name");	
				}
			}
			if (is_integer($name) || is_string($name)) {
				$field->setName($name);//设置名称
			}
			
			foreach ($fieldConfig as $key=>$value) {
				if (in_array($key, array("name", "type", "column", "maxLength", "notNull", "primaryKey", "autoIncrement", "binary", "unsigned", "hasDefault", "defaultValue", "virtual", "expression"), true)) {
					$setter = "set" . $key;
					$field->$setter($value);
				}
				else if (in_array($key, array("hasOne", "hasMany", "belongsTo"), true) && is_array($value)) {
					if (!array_key_exists("type", $value)) {
						$value["type"] = $key;
					}
					$field->setRelation($value);
				}
			}
			$table->addField($field);
			
		}
		return $table;
	}
	
	/**
	 * 从表中自动生成
	 *
	 * @param IDarProvider $provider 驱动
	 * @param string $class 类名
	 * @param array $config  配置
	 * @since 0.2.1
	 */
	public static function autoCreate($provider, $class, $config) {
		$tblName = $config["tblName"];
		$fields = $provider->getSqlMap()->getDriver()->describeTable($tblName);
		$model = $config;
		$model["tblName"] = $tblName;
		$model["fields"] = array();
		foreach ($fields as $field) {
			$name = $field["column"];
			if (isset($config["nameRule"])) {
				switch ($config["nameRule"]) {
					case "java": $name = native::nameToJava($name); break;
					case "c": $name = native::nameToC($name); break;
				}
			}
			$model["fields"][] = array("name" => $name, "column" => $field["column"]);
			if ($field["primaryKey"]) {
				$model["idName"] = native::nameToJava($field["column"]);
			}
		}
		return self::create($class, $model);
	}
}

?>